//
//  SpeedCoach_Importer_AppDelegate.m
//  SpeedCoach Importer
//
//  Created by Roelant Ossewaarde on 4/8/11.
//  Copyright SUNY Buffalo 2011 . All rights reserved.
//

#import "SpeedCoach_Importer_AppDelegate.h"

@implementation SpeedCoach_Importer_AppDelegate

@synthesize window;
@synthesize logMessages;
@synthesize mwvc;

/**
    Returns the support directory for the application, used to store the Core Data
    store file.  This code uses a directory named "SpeedCoach_Importer" for
    the content, either in the NSApplicationSupportDirectory location or (if the
    former cannot be found), the system's temporary directory.
 */

- (NSString *)applicationSupportDirectory {

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
    NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : NSTemporaryDirectory();
    return [basePath stringByAppendingPathComponent:@"SpeedCoach_Importer"];
}


/**
    Creates, retains, and returns the managed object model for the application 
    by merging all of the models found in the application bundle.
 */
 
- (NSManagedObjectModel *)managedObjectModel {

    if (managedObjectModel) return managedObjectModel;
	
    managedObjectModel = [[NSManagedObjectModel mergedModelFromBundles:nil] retain];    
    return managedObjectModel;
}


/**
    Returns the persistent store coordinator for the application.  This 
    implementation will create and return a coordinator, having added the 
    store for the application to it.  (The directory for the store is created, 
    if necessary.)
 */

- (NSPersistentStoreCoordinator *) persistentStoreCoordinator {

    if (persistentStoreCoordinator) return persistentStoreCoordinator;

    NSManagedObjectModel *mom = [self managedObjectModel];
    if (!mom) {
        NSAssert(NO, @"Managed object model is nil");
        NSLog(@"%@:%s No model to generate a store from", [self class], _cmd);
        return nil;
    }

    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSString *applicationSupportDirectory = [self applicationSupportDirectory];
    NSError *error = nil;
    
    if ( ![fileManager fileExistsAtPath:applicationSupportDirectory isDirectory:NULL] ) {
		if (![fileManager createDirectoryAtPath:applicationSupportDirectory withIntermediateDirectories:NO attributes:nil error:&error]) {
            NSAssert(NO, ([NSString stringWithFormat:@"Failed to create App Support directory %@ : %@", applicationSupportDirectory,error]));
            NSLog(@"Error creating application support directory at %@ : %@",applicationSupportDirectory,error);
            return nil;
		}
    }
    
    NSURL *url = [NSURL fileURLWithPath: [applicationSupportDirectory stringByAppendingPathComponent: @"storedata"]];
    persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: mom];
    if (![persistentStoreCoordinator addPersistentStoreWithType:NSXMLStoreType 
                                                configuration:nil 
                                                URL:url 
                                                options:nil 
                                                error:&error]){
        [[NSApplication sharedApplication] presentError:error];
        [persistentStoreCoordinator release], persistentStoreCoordinator = nil;
        return nil;
    }    

    return persistentStoreCoordinator;
}

/**
    Returns the managed object context for the application (which is already
    bound to the persistent store coordinator for the application.) 
 */
 
- (NSManagedObjectContext *) managedObjectContext {

    if (managedObjectContext) return managedObjectContext;

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (!coordinator) {
        NSMutableDictionary *dict = [NSMutableDictionary dictionary];
        [dict setValue:@"Failed to initialize the store" forKey:NSLocalizedDescriptionKey];
        [dict setValue:@"There was an error building up the data file." forKey:NSLocalizedFailureReasonErrorKey];
        NSError *error = [NSError errorWithDomain:@"YOUR_ERROR_DOMAIN" code:9999 userInfo:dict];
        [[NSApplication sharedApplication] presentError:error];
        return nil;
    }
    managedObjectContext = [[NSManagedObjectContext alloc] init];
    [managedObjectContext setPersistentStoreCoordinator: coordinator];

    return managedObjectContext;
}

/**
    Returns the NSUndoManager for the application.  In this case, the manager
    returned is that of the managed object context for the application.
 */
 
- (NSUndoManager *)windowWillReturnUndoManager:(NSWindow *)window {
    return [[self managedObjectContext] undoManager];
}



/**
    Performs the save action for the application, which is to send the save:
    message to the application's managed object context.  Any encountered errors
    are presented to the user.
 */
 
- (IBAction) saveAction:(id)sender {
	NSSavePanel *mySavePanel = [NSSavePanel savePanel];
	[mySavePanel setMessage:@"Specify the filename to save the RAW dump of eprom1"];
	[mySavePanel runModal];

    NSError *error = nil;
    
    if (![[self managedObjectContext] commitEditing]) {
        NSLog(@"%@:%s unable to commit editing before saving", [self class], _cmd);
    }

    if (![[self managedObjectContext] save:&error]) {
        [[NSApplication sharedApplication] presentError:error];
    }
}


/**
    Implementation of the applicationShouldTerminate: method, used here to
    handle the saving of changes in the application managed object context
    before the application terminates.
 */
 
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender {

    if (!managedObjectContext) return NSTerminateNow;

    if (![managedObjectContext commitEditing]) {
        NSLog(@"%@:%s unable to commit editing to terminate", [self class], _cmd);
        return NSTerminateCancel;
    }

    if (![managedObjectContext hasChanges]) return NSTerminateNow;

    NSError *error = nil;
    if (![managedObjectContext save:&error]) {
    
        // This error handling simply presents error information in a panel with an 
        // "Ok" button, which does not include any attempt at error recovery (meaning, 
        // attempting to fix the error.)  As a result, this implementation will 
        // present the information to the user and then follow up with a panel asking 
        // if the user wishes to "Quit Anyway", without saving the changes.

        // Typically, this process should be altered to include application-specific 
        // recovery steps.  
                
        BOOL result = [sender presentError:error];
        if (result) return NSTerminateCancel;

        NSString *question = NSLocalizedString(@"Could not save changes while quitting.  Quit anyway?", @"Quit without saves error question message");
        NSString *info = NSLocalizedString(@"Quitting now will lose any changes you have made since the last successful save", @"Quit without saves error question info");
        NSString *quitButton = NSLocalizedString(@"Quit anyway", @"Quit anyway button title");
        NSString *cancelButton = NSLocalizedString(@"Cancel", @"Cancel button title");
        NSAlert *alert = [[NSAlert alloc] init];
        [alert setMessageText:question];
        [alert setInformativeText:info];
        [alert addButtonWithTitle:quitButton];
        [alert addButtonWithTitle:cancelButton];

        NSInteger answer = [alert runModal];
        [alert release];
        alert = nil;
        
        if (answer == NSAlertAlternateReturn) return NSTerminateCancel;

    }

    return NSTerminateNow;
}

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    logMessages = [[NSMutableArray alloc] init];
	[self log:@"Running..." severity:0];
	[mwvc setProgressLabelToString:@"Ready..."];
	eprom1Data = nil;
	eprom2Data = nil;
	memoryBlock = nil;

	[mwvc hideProgressIndicator];
}

-(void) log:(NSString *)theMessage severity:(int)theSeverity {
	LogMessage *lm = [[LogMessage alloc] initWithMessage:theMessage severity:theSeverity];
	[logMessages addObject:lm];

	[lm release];
	[mwvc updateLogView];
}

- (void)windowDidLoad {
	NSLog(@"app windowdidload called");
}
/**
    Implementation of dealloc, to release the retained variables.
 */
 
- (void)dealloc {

    [window release];
    [managedObjectContext release];
    [persistentStoreCoordinator release];
    [managedObjectModel release];
	
    [super dealloc];
}

- (IBAction)importFromSpeedCoach:(id)sender {
	NSInvocationOperation* theOp = [[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(performImportFromSpeedCoachXL:) object:sender] autorelease];
	NSOperationQueue* aQueue = [[NSOperationQueue alloc] init];
	[aQueue addOperation:theOp];	
	[mwvc setProgressLabelToString:@"Working..."];

}


-(void) updateNumBytesRead:(double)numBytes {
	[mwvc updateProgressIndicatorWithDoubleValue:numBytes];
}

-(void) performImportFromSpeedCoachXL:(id)sender {
	int filedescriptor;
	[self log:@"Starting import from SpeedCoach" severity:0];
	SpeedCoachComms *speedCoach = [[SpeedCoachComms alloc] init];

	if ((filedescriptor = [speedCoach initializeComms]) == -1) {
		[self log:@"COM1/2 could not be initialized. (error code: 1)" severity:2];
		return;
	}
	[mwvc showProgressIndicator];

	if ([speedCoach pingSpeedCoach] == NO) {
		[self log:@"The SpeedCoach is not responding to communications. Please verify it is (a) on, (b) connected, and (c) in PC mode. (error code: 1)" severity:2];
		[speedCoach close];
		[mwvc hideProgressIndicator];

		return;
	}
	[self log:@"The speedcoach is ready for communication." severity:2];
	[mwvc setProgressLabelToString:@"Downloading eprom1 data (1/2) ..."];
	eprom1Data = [speedCoach readEprom:0];
	[mwvc hideProgressIndicator];

	[mwvc showProgressIndicator];
	[mwvc setProgressLabelToString:@"Downloading eprom2 data (2/2) ..."];

	eprom2Data = [speedCoach readEprom:1];
	[self log:@"Done downloading data." severity:0];
	[speedCoach close];
	[mwvc hideProgressIndicator];
	[mwvc setProgressLabelToString:@"Ready..."];

	return;
	// create NSOperation object for the serial i/o
	NSData *theData = [SpeedCoachComms readEprom:filedescriptor eprom:0];
	//	NSData *bufferEprom2 = [self readEprom:fileDescriptor eprom:1];
	//NSLog(@"Updating progress bar");
	if ([NSApp sendAction:@selector(dataReady:) to:nil from:self] == NO) {
		NSLog(@"AppplicationController:performImportFromSpeedCoachXL:Responder chain does not respond to a message, debug!!!!");
	}
	NSString *filename = @"/tmp/speedcoach.eprom1";
	NSLog(@"AppplicationController:performImportFromSpeedCoachXL:writing data buffer to file %@!", filename);
	
//	[bufferEprom1 writeToFile:filename atomically:NO];
	//	[bufferEprom2 writeToFile:@"/tmp/speedcoach.eprom2" atomically:NO];
	NSLog(@"AppplicationController:performImportFromSpeedCoachXL:calling importFromDumpBuffer with bufferEprom1");
	
//	[[self myLibraryWindowController] importFromDumpBuffer:bufferEprom1];
//	 */
	return;
}


- (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)anItem {
	if (anItem == saveRawEprom1MenuItem && eprom1Data == nil) return NO;
	if (anItem == saveRawEprom2MenuItem && eprom2Data == nil) return NO;
	if (anItem == exportMemoryBlock && memoryBlock == nil) return NO;
	return YES;
}

-(IBAction) readEprom:(id) sender {
	NSOpenPanel *myOpenPanel = [NSOpenPanel openPanel];
	int result = [myOpenPanel runModal];
	if (result == NSFileHandlingPanelOKButton) {
		NSURL *url = [myOpenPanel URL];
		NSString *logMessage;
		NSData *dataBlock = [NSData dataWithContentsOfURL:url];
		if ([SpeedCoachMemoryBlock isValidEprom1:dataBlock]) {
			memoryBlock = [[SpeedCoachMemoryBlock alloc] initWithData:dataBlock];
			logMessage = [NSString stringWithFormat:@"Read data from file with URL %@", [url absoluteURL]];
			
		} else {
			logMessage = [NSString stringWithFormat:@"File with URL %@ is not a valid EPROM1 RAW file (error x)", [url absoluteURL]];
		}
		[self log:logMessage severity:2];
	}
}

-(IBAction) saveEprom:(id) sender {
	NSSavePanel *mySavePanel = [NSSavePanel savePanel];
	int result = [mySavePanel runModal];
	if (result == NSFileHandlingPanelOKButton) {
		NSURL *url = [mySavePanel URL];
		NSString *logMessage;
		if (sender == saveRawEprom1MenuItem) {
			[eprom1Data writeToURL:url atomically:YES];
			logMessage = [NSString stringWithFormat:@"Saved eprom1 to file with URL %@", [url absoluteURL]];
		} else if (sender == saveRawEprom2MenuItem) {
			[eprom2Data writeToURL:url atomically:YES];
			logMessage = [NSString stringWithFormat:@"Saved eprom2 to file with URL %@", [url absoluteURL]];
		}
		[self log:logMessage severity:2];
	}
}

-(IBAction) export:(id) sender {
	NSSavePanel *mySavePanel = [NSSavePanel savePanel];
	int result = [mySavePanel runModal];
	if (result == NSFileHandlingPanelOKButton) {
		NSURL *url = [mySavePanel URL];
		[memoryBlock parse];
		NSString *saveString = [[NSString alloc] initWithString:@""];
		NSArray *array = (NSArray *) [memoryBlock automem];
		saveString = [saveString stringByAppendingFormat:@"%@", [(SCWorkoutDataBlock *)[array objectAtIndex:0] csvHeader]];

		for (SCWorkoutDataBlock *db in array) {
			saveString = [saveString stringByAppendingFormat:@"%@", [db toCSV]];

		}
		array = (NSArray *) [memoryBlock workoutmem];
		for (SCWorkoutDataBlock *db in array) {
			saveString = [saveString stringByAppendingFormat:@"%@", [db toCSV]];
			
		}
		[saveString writeToURL:url atomically:YES encoding:NSUTF8StringEncoding error:NULL ] ;
			 

		NSString *logMessage;
		logMessage = [NSString stringWithFormat:@"Exported CSV to file with URL %@", [url absoluteURL]];
		[self log:logMessage severity:2];
	}

	
}

@end
